package com.wing.cabinet.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wing.cabinet.dao.StorageInventoryInoutDao;
import com.wing.cabinet.model.entity.CellInventoryInout;
import com.wing.cabinet.model.entity.CellInventoryInoutDetail;
import com.wing.cabinet.model.entity.StorageInventoryInout;
import com.wing.cabinet.model.entity.StorageInventoryInoutDetail;
import com.wing.cabinet.model.request.StorageInventoryInoutForm;
import com.wing.cabinet.model.response.*;
import com.wing.common.utils.JsonResult;
import com.wing.user.feign.UserClient;
import com.wing.user.model.response.DepartmentVO;
import com.wing.util.PulsarCommons;
import com.wing.util.PulsarUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Stream;

/**
 * 暂存柜存刀/取刀;存/取维修/回收刀-ServiceImpl
 *
 * @author
 */

@Service
@Slf4j
public class StorageInventoryInoutServiceImpl extends ServiceImpl<StorageInventoryInoutDao, StorageInventoryInout> implements StorageInventoryInoutService {

    @Autowired
    private StorageInventoryUncheckService inventoryUncheckService;

    @Lazy
    @Autowired
    private StorageInventoryInoutDetailService storageInventoryInoutDetailService;
    @Lazy
    @Autowired
    private CellInventoryInoutService inventoryInoutService;
    @Lazy
    @Autowired
    private CellInventoryInoutDetailService inventoryInoutDetailService;
    @Autowired
    private UserClient userClient;
    private ExecutorService executorService = Executors.newFixedThreadPool(10);

    @Value("${pulsar.client.topicUrl}")
    private String topicUrl;


//    @Autowired
//    private StorageInventoryInoutService inventoryInoutService;

//    @Autowired
//    private StorageInventoryInoutDetailService storageInventoryInoutDetailService;

    @Autowired
    private CheckedInventoryInoutDetailService checkedInventoryInoutDetailService;


    @Override
    public int add(StorageInventoryInoutForm storageInventoryInoutForm) {

        //校验

        StorageInventoryInout storageInventoryInout =new StorageInventoryInout();
        CopyOptions copyOptions = CopyOptions.create()
        .setEditable(StorageInventoryInout.class)
        .setIgnoreError(true)
        .setIgnoreNullValue(true);
        BeanUtil.copyProperties(storageInventoryInoutForm, storageInventoryInout, copyOptions);

        return baseMapper.insert(storageInventoryInout);
    }

    @Override
    public List<StorageInventoryInoutVO> list4app(Map<String, Object> params) {
        return baseMapper.list4app(params);
    }

    @Override
    public Page<StorageInventoryInoutVO> pageList4app(Page page, Map<String, Object> params) {
        List<StorageInventoryInoutVO> list = baseMapper.list4app(page, params);
        for(StorageInventoryInoutVO item : list){
            JsonResult<DepartmentVO> jsonResult = userClient.getDepartmentVOById(item.getDepartmentId());
            if(null != jsonResult && null != jsonResult.getData()) {
                item.setCostCenter(jsonResult.getData().getCostCenter());
            }
        }
        page.setRecords(list);
        return page;
    }

    @Override
    public Page<StorageInventoryInoutVO> pageList(Page page, Map<String, Object> params) {
        List<StorageInventoryInoutVO> list = baseMapper.list(page, params);
        for(StorageInventoryInoutVO item : list){
            JsonResult<DepartmentVO> jsonResult = userClient.getDepartmentVOById(item.getDepartmentId());
            if(null != jsonResult && null != jsonResult.getData()) {
                item.setCostCenter(jsonResult.getData().getCostCenter());
            }
        }
        page.setRecords(list);
        return page;
    }

    @Override
    public Page<StorageInventoryInoutVO> pageList4OldNew(Page page, Map<String, Object> params) {
        List<StorageInventoryInoutVO> list = baseMapper.list4OldNew(page, params);
        for(StorageInventoryInoutVO item : list){
            JsonResult<DepartmentVO> jsonResult = userClient.getDepartmentVOById(item.getDepartmentId());
            if(null != jsonResult && jsonResult.getData() != null) {
                item.setCostCenter(jsonResult.getData().getCostCenter());
            }
        }
        page.setRecords(list);
        return page;
    }

    @Override
    public StorageInventoryInoutVO get4appById(Long id) {
        return baseMapper.get4appById(id);
    }

    @Override
    public int update4Notify(Integer status,Long notifyUserId, String notifyUserName, Long checkResultId,Long supplierId,String supplierName) {
        return baseMapper.update4Notify(status,notifyUserId,notifyUserName,checkResultId,supplierId,supplierName);
    }

    @Override
    public StorageInventoryInoutVO get4appByInOutIdAndSkuCode(Long id, String skuCode) {
        return baseMapper.get4appByInOutIdAndSkuCode(id,skuCode);
    }

    @Override
    public List<StorageInventoryInoutVO> exportList(Map<String, Object> params) {
        return baseMapper.list(params);
    }

    @Override
    public List<OldNewStorageExportVO> getOldNewStorageExportVOExport(Map<String, Object> params) {
        return baseMapper.getOldNewStorageExportVOExport(params);
    }

    @Override
    public List<TemporaryStorageExportVO> getTemporaryStorageExport(Map<String, Object> params) {
        return baseMapper.getTemporaryStorageExport(params);
    }

    @Override
    public List<StorageRecycleInventoryInoutVO> exportRecycleList(Map<String, Object> params) {
        return baseMapper.list4Export(params);
    }

    @Override
    public List<StorageTempInventoryOutVO> exportOutList(Map<String, Object> params) {
        return baseMapper.exportOutList(params);
    }

    // 此处的Transactional注解 原因: 无事务方法调用有事务方法是无法开启事务的
    @Transactional
    @Override
    public void sendMsg() {
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            syncDate();
                        } catch (Exception e) {
                            log.error("syn fail", e);
                        }
                    }

                });
            }
        });


    }

    @Override
    public Page<StorageInventoryInoutVO> pageListNew(Page page, Map<String, Object> params) {
        List<StorageInventoryInoutVO> list = baseMapper.pageListNew(page, params);
        /*for(StorageInventoryInoutVO item : list){
            JsonResult<DepartmentVO> jsonResult = userClient.getDepartmentVOById(item.getDepartmentId());
            item.setCostCenter(jsonResult.getData().getCostCenter());
        }*/
        page.setRecords(list);
        return page;
    }

    /**
     * 此方法 为查询syns_time字段为空的数据 mq同步
     * cab_storage_inventory_inout   暂存柜存刀
     * cab_storage_inventory_inout_detail 暂存柜存刀明细
     * cab_cell_inventory_inout 售刀柜上货
     * cab_cell_inventory_inout_detail  售刀柜上货明细
     *
     */
    private void syncDate() {
        LambdaQueryWrapper<StorageInventoryInout>lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.isNull(StorageInventoryInout::getSynsTime);
        List<StorageInventoryInout> list = this.list(lambdaQueryWrapper);
        try {
            if (list.size()>0){
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("type", "addOrUpdate");
           /*     Stream.iterate(0,i -> i+1).limit(list.size()).forEach(i -> {
                    list.get(i).setSynsTime(LocalDateTime.now());
                });*/
                for (StorageInventoryInout storageInventoryInout : list){
                    storageInventoryInout.setSynsTime(LocalDateTime.now());
                    jsonObject.put("data", storageInventoryInout);
                    PulsarUtils.send(topicUrl+ PulsarCommons.STORAGE_INVENTORY_INOUT_TOPIC,jsonObject.toJSONString());
                    this.updateById(storageInventoryInout);
                }

            }
        }catch (Exception e){
            log.error("sync StorageInventoryInoutServiceImpl syncDate err 同步失败",e);
            Stream.iterate(0,i -> i+1).limit(list.size()).forEach(i -> {
                list.get(i).setIsSyns(StorageInventoryInout.IsSyns.no);
                this.updateById(list.get(i));
            });
        }

        LambdaQueryWrapper<StorageInventoryInoutDetail> storageInventoryInoutDetailLambdaQueryWrapper= new LambdaQueryWrapper<>();
        storageInventoryInoutDetailLambdaQueryWrapper.isNull(StorageInventoryInoutDetail::getSynsTime);
        List<StorageInventoryInoutDetail> storageInventoryInoutDetailList = storageInventoryInoutDetailService.list(storageInventoryInoutDetailLambdaQueryWrapper);
        if (storageInventoryInoutDetailList.size()>0){
            try {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("type", "addOrUpdate");
                Map<Long,String>map = new HashMap<>();
                Stream.iterate(0,i->i+1).limit(storageInventoryInoutDetailList.size()).forEach(integer -> {
                    storageInventoryInoutDetailList.get(integer).setSynsTime(LocalDateTime.now());
                    map.put(storageInventoryInoutDetailList.get(integer).getId(),storageInventoryInoutDetailList.get(integer).getSkuCode());
                    storageInventoryInoutDetailList.get(integer).setSkuCode(storageInventoryInoutDetailList.get(integer).getEnterpriseCode()+"-"+ storageInventoryInoutDetailList.get(integer).getSkuCode());
                });
                jsonObject.put("data", storageInventoryInoutDetailList);
                PulsarUtils.send(topicUrl+ PulsarCommons.STORAGE_INVENTORY_INOUT_DETAILS_TOPIC,jsonObject.toJSONString());

                for (int i = 0; i < storageInventoryInoutDetailList.size(); i++) {
                    Set<Long> keySet = map.keySet();
                    for (Long id : keySet){
                        if (storageInventoryInoutDetailList.get(i).getId().equals(id)){
                            storageInventoryInoutDetailList.get(i).setSkuCode(map.get(id));
                            storageInventoryInoutDetailService.updateById(storageInventoryInoutDetailList.get(i));
                        }
                    }
                }

            }catch (Exception e){
                log.error("sync StorageInventoryInoutServiceImpl syncDate err 同步失败",e);
                Stream.iterate(0,i->i+1).limit(storageInventoryInoutDetailList.size()).forEach(integer -> {
                    storageInventoryInoutDetailList.get(integer).setIsSyns(StorageInventoryInoutDetail.IsSyns.no);
                    storageInventoryInoutDetailService.updateById(storageInventoryInoutDetailList.get(integer));
                });
            }
        }


        LambdaQueryWrapper<CellInventoryInout>inoutLambdaQueryWrapper = new LambdaQueryWrapper<CellInventoryInout>().isNull(CellInventoryInout::getSynsTime);
        List<CellInventoryInout> inoutList = inventoryInoutService.list(inoutLambdaQueryWrapper);
        if (inoutList.size()>0){
            try {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("type", "addOrUpdate");
              /*  Stream.iterate(0,i->i+1).limit(inoutList.size()).forEach(integer -> {
                    inoutList.get(integer).setSynsTime(LocalDateTime.now());
                });
                    jsonObject.put("data", inoutList);
                PulsarUtils.send(topicUrl+ PulsarCommons.CELL_INVENTORY_INOUT_TOPIC,jsonObject.toJSONString());*/
                for (CellInventoryInout cellInventoryInout : inoutList){
                    cellInventoryInout.setSynsTime(LocalDateTime.now());
                    jsonObject.put("data", cellInventoryInout);
                    PulsarUtils.send(topicUrl+ PulsarCommons.CELL_INVENTORY_INOUT_TOPIC,jsonObject.toJSONString());
                    inventoryInoutService.updateById(cellInventoryInout);
                }
            }catch (Exception e){
                log.error("sync StorageInventoryInoutServiceImpl syncDate err 同步失败",e);
                Stream.iterate(0,i->i+1).limit(inoutList.size()).forEach(integer -> {
                    inoutList.get(integer).setIsSyns(0);
                    inventoryInoutService.updateById(inoutList.get(integer));
                });
            }
        }


        LambdaQueryWrapper<CellInventoryInoutDetail>inoutLambdaDetailQueryWrapper = new LambdaQueryWrapper<CellInventoryInoutDetail>().isNull(CellInventoryInoutDetail::getSynsTime);
        List<CellInventoryInoutDetail> inventoryInoutDetailList = inventoryInoutDetailService.list(inoutLambdaDetailQueryWrapper);
        if (inventoryInoutDetailList.size()>0){
            try {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("type", "addOrUpdate");

                for (CellInventoryInoutDetail detail : inventoryInoutDetailList){
                    detail.setSynsTime(LocalDateTime.now()).setSkuCode(detail.getEnterpriseCode()+"-"+detail.getSkuCode());
                    jsonObject.put("data", detail);
                    PulsarUtils.send(topicUrl+ PulsarCommons.CELL_INVENTORY_INOUT_DETAIL_TOPIC,jsonObject.toJSONString());
                    // 修改同步时间
                    CellInventoryInoutDetail inoutDetail = inventoryInoutDetailService.getById(detail.getId());
                    inoutDetail.setSynsTime(LocalDateTime.now());
                    inventoryInoutDetailService.updateById(inoutDetail);

                }
            }catch (Exception e){
                log.error("sync StorageInventoryInoutServiceImpl syncDate err 同步失败",e);
                Stream.iterate(0,i->i+1).limit(inventoryInoutDetailList.size()).forEach(integer -> {
                    inventoryInoutDetailList.get(integer).setIsSyns(0);
                    inventoryInoutDetailService.updateById(inventoryInoutDetailList.get(integer));
                });
            }
        }

    }



    /*@Override
    public List<StorageInventoryInoutVO> ecxportList(Map<String, Object> params) {
        List<StorageInventoryInoutVO> list = baseMapper.list(params);
        return list;
    }*/

}
